package com.seahorse.youliao.security.sms;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.seahorse.youliao.security.handler.MyAuthenticationException;
import com.seahorse.youliao.util.HttpRequestUtil;
import com.seahorse.youliao.utils.SpringContextUtils;
import com.zengtengpeng.operation.RedissonObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @description: 短信校验过滤器
 * @author: Mr.Song
 * @create: 2020-11-23 21:25
 **/
public class SmsCodeLoginFilter extends AbstractAuthenticationProcessingFilter {


    public static final String SPRING_SECURITY_MOBILE_KEY = "mobile";
    public static final String SPRING_SECURITY_CODE_KEY = "code";
    private String mobileParameter = SPRING_SECURITY_MOBILE_KEY;
    private String codeParameter = SPRING_SECURITY_CODE_KEY;
    private boolean postOnly = true;

    public SmsCodeLoginFilter(AuthenticationManager authManager,
                              AuthenticationSuccessHandler successHandler,
                              AuthenticationFailureHandler failureHandler,
                              ApplicationEventPublisher eventPublisher) {
        super(new AntPathRequestMatcher("/mobile/login", "POST"));
        setAuthenticationManager(authManager);
        setAuthenticationSuccessHandler(successHandler);
        setAuthenticationFailureHandler(failureHandler);
        setApplicationEventPublisher(eventPublisher);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {



        if (this.postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        } else {
            String body = HttpRequestUtil.getBody(request);
            JSONObject jsonObject = JSON.parseObject(body);
            String mobile = jsonObject.getString(mobileParameter);
            String code = jsonObject.getString(codeParameter);

            //校验code
            RedissonObject redissonObject = (RedissonObject)SpringContextUtils.getBeanByClass(RedissonObject.class);
            String msgCode = redissonObject.getValue(mobile);

            // 清除短信验证码
            redissonObject.delete(mobile);
            if (StringUtils.isBlank(msgCode)) {
                logger.error("验证码不存在或已过期");
                throw new MyAuthenticationException("验证码不存在或已过期");
            }
            if (StringUtils.isBlank(code) || !code.equalsIgnoreCase(msgCode)) {
                logger.error("验证码错误");
                throw new MyAuthenticationException("验证码错误");
            }

            if (mobile == null) {
                mobile = "";
            }

            if (code == null) {
                code = "";
            }

            mobile = mobile.trim();
            SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile,code);
            this.setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }


    protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
    }

}
